package com.android.systemui.ios.views;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.res.TypedArray;
import android.database.ContentObserver;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
import android.graphics.RectF;
import android.os.BatteryManager;
import android.os.Handler;
import android.provider.Settings;
import android.util.AttributeSet;
import android.view.View;
import static java.lang.annotation.RetentionPolicy.SOURCE;

import androidx.annotation.IntDef;

import com.android.systemui.ios.R;

import java.lang.annotation.Retention;

public class BatteryView extends View {

	@Retention(SOURCE)
    @IntDef({MODE_DEFAULT, MODE_ON, MODE_OFF, MODE_ESTIMATE})
	public @interface BatteryPercentMode {}
    public static final int MODE_DEFAULT = 0;
    public static final int MODE_ON = 1;
    public static final int MODE_OFF = 2;
    public static final int MODE_ESTIMATE = 3;
	private int mShowPercentMode = MODE_DEFAULT;

    private final float WIDTH = dpToPx(32);
    private final float HEIGHT = dpToPx(16);
    private final float RADIUS = dpToPx(4);
    private final float INSET = dpToPx(2);
    private final float SMALL_CHG = dpToPx(4.5f);

    private int mLevel = 100;
    private boolean isPlugIn = false;
    private boolean isDark = false;
    private float density = 0;
    private boolean useInternetPercent = true;
    private boolean isShowPercent = false;

    private final Path mChargePath = new Path();
    private final Path mChargeBgPath = new Path();
    private final Path mPercentChargePath = new Path();

    private final RectF mBorderRect = new RectF();
    private final RectF mFillRect = new RectF();
    private final RectF mLevelRect = new RectF();
    private final RectF mSharpRect = new RectF();
    private final RectF mClipRect = new RectF();

    private final Paint mChargingPaint = new Paint();
    private final Paint mChargingBgPaint = new Paint();
    private final Paint mBorderPaint = new Paint();
    private final Paint mFillPaint = new Paint();
    private final Paint mSharpPaint = new Paint();

    private final Rect mTextBorder = new Rect();
    private final PorterDuffXfermode mDuff = new PorterDuffXfermode(PorterDuff.Mode.DST_OUT);

    public BatteryView(Context context) {
        this(context, null, 0);
    }

    public BatteryView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public BatteryView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);

        if (attrs != null) {
            TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.BatteryView, defStyleAttr, 0);
            useInternetPercent = a.getBoolean(R.styleable.BatteryView_internetPercent, true);
            a.recycle();
        }

        mBorderPaint.setAntiAlias(true);
        mBorderPaint.setStrokeWidth(dpToPx(1.2f));
        mBorderPaint.setStyle(Paint.Style.STROKE);

        mFillPaint.setAntiAlias(true);
        mFillPaint.setStyle(Paint.Style.FILL);

        mSharpPaint.setAntiAlias(true);
        mSharpPaint.setStyle(Paint.Style.FILL);

        mChargingPaint.setAntiAlias(true);
        mChargingPaint.setFakeBoldText(true);
        mChargingPaint.setTextSize(dpToPx(12));
        mChargingPaint.setTextAlign(Paint.Align.CENTER);
        mChargingPaint.setStyle(Paint.Style.FILL);

        mChargingBgPaint.setAntiAlias(true);
        mChargingBgPaint.setStyle(Paint.Style.FILL);

        mBorderRect.set(dpToPx(1), dpToPx(1), WIDTH - dpToPx(4f), HEIGHT - dpToPx(1));

        mFillRect.set(mBorderRect);
        mFillRect.inset(INSET, INSET);

        mLevelRect.set(mFillRect);

        mSharpRect.left = dpToPx(0.5f);
        mSharpRect.top = mBorderRect.height() / 3 + dpToPx(1.5f);
        mSharpRect.right = mBorderRect.right + dpToPx(3f);
        mSharpRect.bottom = mBorderRect.height() * 2 / 3 + dpToPx(1.5f);

        mClipRect.set(mSharpRect);
        mClipRect.left = mClipRect.right - dpToPx(1.5f);

        mChargeBgPath.moveTo(dpToPx(15.5f), dpToPx(0.5f));
        mChargeBgPath.lineTo(dpToPx(9.5f), dpToPx(9));
        mChargeBgPath.lineTo(dpToPx(14f), dpToPx(9));
        mChargeBgPath.lineTo(dpToPx(11f), dpToPx(15f));
        mChargeBgPath.lineTo(dpToPx(18f), dpToPx(6.5f));
        mChargeBgPath.lineTo(dpToPx(13.5f), dpToPx(6.5f));
        mChargeBgPath.close();

        mChargePath.moveTo(dpToPx(16), 0);
        mChargePath.lineTo(dpToPx(10), dpToPx(8.5f));
        mChargePath.lineTo(dpToPx(14.5f), dpToPx(8.5f));
        mChargePath.lineTo(dpToPx(11.5f), dpToPx(14.5f));
        mChargePath.lineTo(dpToPx(18.5f), dpToPx(6f));
        mChargePath.lineTo(dpToPx(14f), dpToPx(6f));
        mChargePath.close();

        mPercentChargePath.moveTo(dpToPx(24.5f), dpToPx(4f));
        mPercentChargePath.lineTo(dpToPx(21.5f), dpToPx(8f));
        mPercentChargePath.lineTo(dpToPx(23f), dpToPx(8f));
        mPercentChargePath.lineTo(dpToPx(22f), dpToPx(11.5f));
        mPercentChargePath.lineTo(dpToPx(25.5f), dpToPx(7f));
        mPercentChargePath.lineTo(dpToPx(24f), dpToPx(7f));
        mPercentChargePath.close();
    }

    @Override
    protected void onFinishInflate() {
        super.onFinishInflate();
        isShowPercent = Settings.Secure.getInt(getContext().getContentResolver(), "battery_percentage", 0) == 1;
        updateColors();
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        if (useInternetPercent && isShowPercent) {
            canvas.drawRoundRect(mBorderRect, RADIUS, RADIUS, mFillPaint);
            String level = String.valueOf(mLevel);
            mChargingPaint.getTextBounds(level, 0, level.length(), mTextBorder);
            float x = mBorderRect.width() / 2.0f;

            canvas.save();
            mChargingPaint.setXfermode(mDuff);
            if (isPlugIn) {
                x -= SMALL_CHG / 2;
                canvas.drawPath(mPercentChargePath, mChargingPaint);
            }
            canvas.drawText(level, x, (mBorderRect.height() - mTextBorder.height()) / 2 + mTextBorder.height() + dpToPx(1), mChargingPaint);
            canvas.restore();
        } else {
            canvas.drawRoundRect(mBorderRect, RADIUS, RADIUS, mBorderPaint);
            canvas.drawRoundRect(mLevelRect, RADIUS - dpToPx(1), RADIUS - dpToPx(1), mFillPaint);

            if (isPlugIn) {
                mChargingPaint.setXfermode(null);
                canvas.drawPath(mChargeBgPath, mChargingBgPaint);
                canvas.drawPath(mChargePath, mChargingPaint);
            }
        }
        canvas.save();
        canvas.clipRect(mClipRect);
        canvas.drawRoundRect(mSharpRect, dpToPx(9), dpToPx(9), mSharpPaint);
        canvas.restore();
    }

    public void setIconsDark(boolean dark) {
        if (isDark != dark) {
            isDark = dark;
            updateColors();
        }
    }

    private void updateColors() {
        final float width = mFillRect.width() * mLevel / 100 + 2;
        mLevelRect.right = mLevelRect.left + Math.min(width, mFillRect.width());
        if (isDark) {
            mBorderPaint.setColor(0xff939393);
            mSharpPaint.setColor(0xff939393);
            mChargingBgPaint.setColor(0xff939393);
            mChargingPaint.setColor(0xff000000);
        } else {
            mBorderPaint.setColor(0x80e0e0e0);
            mSharpPaint.setColor(0x80e0e0e0);
            mChargingBgPaint.setColor(0xf08f8f8f);
            mChargingPaint.setColor(0xffffffff);
        }
        if (mLevel < 20) {
            mFillPaint.setColor(0xffeb4d3d);
        } else {
            if (isPlugIn) {
                mFillPaint.setColor(0xff34c759);
            } else {
                if (isDark) {
                    mFillPaint.setColor(0xff000000);
                } else {
                    mFillPaint.setColor(0xffffffff);
                }
            }
        }
        postInvalidate();
    }

    @Override
    protected void onAttachedToWindow() {
        super.onAttachedToWindow();
        IntentFilter filter = new IntentFilter();
        filter.addAction(Intent.ACTION_BATTERY_CHANGED);
        getContext().registerReceiver(mReceiver, filter);
        getContext().getContentResolver().registerContentObserver(Settings.Secure.getUriFor(
                "battery_percentage"), false, mObserver);
    }

    @Override
    protected void onDetachedFromWindow() {
        super.onDetachedFromWindow();
        getContext().unregisterReceiver(mReceiver);
        getContext().getContentResolver().unregisterContentObserver(mObserver);
    }

    private float dpToPx(float dps) {
        if (density == 0) {
            density = getResources().getDisplayMetrics().density;
        }
        return density * dps;
    }

    private final ContentObserver mObserver = new ContentObserver(new Handler()) {

        @Override
        public void onChange(boolean selfChange) {
            super.onChange(selfChange);
            isShowPercent = Settings.Secure.getInt(getContext().getContentResolver(), "battery_percentage", 0) == 1;
            postInvalidate();
        }
    };

    private final BroadcastReceiver mReceiver = new BroadcastReceiver() {

        @Override
        public void onReceive(Context context, Intent intent) {
            final String action = intent.getAction();
            if (Intent.ACTION_BATTERY_CHANGED.equals(action)) {
                int level = (int) (100f
                        * intent.getIntExtra(BatteryManager.EXTRA_LEVEL, 0)
                        / intent.getIntExtra(BatteryManager.EXTRA_SCALE, 100));
                boolean plugIn = intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, 0) != 0;
                if (level != mLevel || plugIn != isPlugIn) {
                    mLevel = level;
                    isPlugIn = plugIn;
                    updateColors();
                }
            }
        }
    };

	public void setForceShowPercent(boolean show) {
        setPercentShowMode(show ? MODE_ON : MODE_DEFAULT);
    }

    /**
     * Force a particular mode of showing percent
     *
     * 0 - No preference
     * 1 - Force on
     * 2 - Force off
     * @param mode desired mode (none, on, off)
     */
    public void setPercentShowMode(@BatteryPercentMode int mode) {
        mShowPercentMode = mode;//mode maybe add later
        updateColors();
    }

    public void onDarkChanged(Rect area, float darkIntensity, int tint) {
        setIconsDark(darkIntensity == 1);
    }
}
